K8s Pod 控制器

之前我们共使用两种方式创建 Pod。一种是 kubectl run,另一种为 kubectl create + 配置文件。当我们将以 kubectl create 创建的 Pod 删除之后,Pod 是不会重新被创建的,也就是说此类 Pod 是没有被控制器管理的,删除之后就没有了。而使用 kubectl run 创建的 Pod 是被控制器管理的,删除之后还会重新启动,达到你定义的状态。ReplicationController 是K8s之前的唯一一个控制器,因为其太过庞大,所以目前不怎么使用。从而出现的 ReplicaSet 等控制器成为主流。

ReplicaSet

查看定义

Kubernetes 并不建议我们直接使用 ReplicaSet 控制器。而是建议我们使用 Deployment 控制器。Deployment 通过控制 ReplicaSet 来控制 Pod,是对 ReplicaSet 的进一步封装,拥有更强大的功能。
查看 ReplicaSet 的字段

1
kubectl explain rs

ReplicaSet 的 spec 中有三个核心的部分组成,分别为副本数(replicas),标签选择器(selector),Pod 模版(template)。template 中 spec 的定义和我们之前定义的 Pod 方式一致,都有什么 containers,nodeName,nodeSelector等等。

1
kubectl explain rs.spec

创建资源

定义一个 ReplicaSet,标签选择规则为 matchLabels(所有标签都必须满足)。注意,这里创建的 Pod 的标签要和 ReplicaSet标签选择器中的一致,这样才能将创建出来的 Pod 和选择器进行关联。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: apps/v1
kind:
metadata:
name: myapp
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
release: test
template:
metadata:
name: myapp-pod
labels:
app: myapp
release: test
env: local
spec:
containers:
- name: myapp-container
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80

创建 Pod

1
kubectl create -f rs-demo.yaml

查看 ReplicaSet。可以看到期待的两个,当前为两个,处于 READY 装状态的为两个。

1
kubectl get rs

1
2
3
[root@k8s001 rexyan]# kubectl get rs 
NAME DESIRED CURRENT READY AGE
myapp 2 2 2 45s

查看 Pod 列表(注意,Pod 的 name 是以控制器的名称加上随机字符串组成,而不是自己的定义的 myapp-pod)

1
kubectl get pods
1
2
3
4
[root@k8s001 rexyan]# kubectl get pods 
NAME READY STATUS RESTARTS AGE
myapp-hl4wg 1/1 Running 0 36s
myapp-xrb9n 1/1 Running 0 36s

查看 Pod 详细信息

1
kubectl describe pods + pod 名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
[root@k8s001 rexyan]# kubectl describe pods myapp-hl4wg
Name: myapp-hl4wg
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: k8s003/172.20.245.193
Start Time: Sun, 26 May 2019 20:03:39 +0800
Labels: app=myapp
env=local
release=test
Annotations: <none>
Status: Running
IP: 10.24.2.2
Controlled By: ReplicaSet/myapp
Containers:
myapp-container:
Container ID: docker://b3df7d29352b61057535ebe7a48ae27d47105029d17c42298a9938a89c0efd5e
Image: ikubernetes/myapp:v1
Image ID: docker-pullable://docker.io/ikubernetes/myapp@sha256:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Sun, 26 May 2019 20:03:42 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-wpmp4 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-wpmp4:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-wpmp4
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 98s default-scheduler Successfully assigned default/myapp-hl4wg to k8s003
Normal Pulling 97s kubelet, k8s003 Pulling image "ikubernetes/myapp:v1"
Normal Pulled 95s kubelet, k8s003 Successfully pulled image "ikubernetes/myapp:v1"
Normal Created 95s kubelet, k8s003 Created container myapp-container
Normal Started 95s kubelet, k8s003 Started container myapp-container

查看 pods 的标签

1
kubectl get pods --show-labels
1
2
3
4
[root@k8s001 rexyan]# kubectl get  pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myapp-hl4wg 1/1 Running 0 2m35s app=myapp,env=local,release=test
myapp-xrb9n 1/1 Running 0 2m35s app=myapp,env=local,release=test

修改标签

删除名称为 myapp-hl4wg 的 Pod,会看到一个新的 Pod 会被创建出来,因为我们期待的数量为 2 个。

1
2
3
4
5
6
7
8
9
10
11
12
[root@k8s001 rexyan]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myapp-hl4wg 1/1 Running 0 31m app=myapp,env=local,release=test
myapp-xrb9n 1/1 Running 0 31m app=myapp,env=local,release=test

[root@k8s001 rexyan]# kubectl delete pods myapp-hl4wg
pod "myapp-hl4wg" deleted

[root@k8s001 rexyan]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myapp-d6q5r 1/1 Running 0 4s app=myapp,env=local,release=test
myapp-xrb9n 1/1 Running 0 32m app=myapp,env=local,release=test

修改其中一个 Pod 的标签,将其 app=myapp 改为 app=app。会看到会新建一个 Pod 起来,被修改 Pod 现在就不属于任何控制器了。

1
2
3
4
5
6
7
8
9
10
11
12
[root@k8s001 rexyan]# kubectl label pods myapp-d6q5r app=app --overwrite
pod/myapp-d6q5r labeled

[root@k8s001 rexyan]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myapp-d6q5r 1/1 Running 0 3m36s app=app,env=local,release=test
myapp-kb94h 1/1 Running 0 3s app=myapp,env=local,release=test
myapp-xrb9n 1/1 Running 0 35m app=myapp,env=local,release=test

[root@k8s001 rexyan]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp 2 2 2 36m myapp-container ikubernetes/myapp:v1 app=myapp,release=test

动态扩容

动态修改 ReplicaSet。myapp 为 ReplicaSet 的名称,并且副本为改成 5 个。改完后就会立即生效。

1
[root@k8s001 rexyan]# kubectl edit rs myapp
1
2
3
4
5
6
7
8
9
10
11
12
[root@k8s001 rexyan]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myapp-68p22 1/1 Running 0 4s app=myapp,env=local,release=test
myapp-b9x4x 1/1 Running 0 4s app=myapp,env=local,release=test
myapp-bphsr 1/1 Running 0 4s app=myapp,env=local,release=test
myapp-d6q5r 1/1 Running 0 9m34s app=app,env=local,release=test
myapp-kb94h 1/1 Running 0 6m1s app=myapp,env=local,release=test
myapp-xrb9n 1/1 Running 0 41m app=myapp,env=local,release=test

[root@k8s001 rexyan]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp 5 5 5 41m myapp-container ikubernetes/myapp:v1 app=myapp,release=test

或者使用 scale 命令进行修改

1
2
3
4
5
6
7
8
9
10
11
12
[root@k8s001 rexyan]#  kubectl scale --replicas=2 rs myapp
replicaset.extensions/myapp scaled

[root@k8s001 rexyan]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp 2 2 2 46m myapp-container ikubernetes/myapp:v1 app=myapp,release=test

[root@k8s001 rexyan]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myapp-d6q5r 1/1 Running 0 14m app=app,env=local,release=test
myapp-kb94h 1/1 Running 0 10m app=myapp,env=local,release=test
myapp-xrb9n 1/1 Running 0 46m app=myapp,env=local,release=test

滚动升级

使用 edit 编辑镜像版本之后,Pod 是不会自动更新的,我们需要将 Pod 删除,然后让其自动重新构建,这样构建出来的才是新版镜像版本的 Pod。这里有两种方式,让其服务过度到新镜像版本的服务,第一种为一个一个的删除 Pod,让其重新一个一个的构建。另一种为构建一个新的 ReplicaSet,测试没问题后,在将新的 ReplicaSet 挂载到 Service 上去,并将以前老的 ReplicaSet 在 service 上摘除。Deployment 就是采用的第二种思想,Deployment 可以管理多个 ReplicaSet,但是可用的只有一个,这样也可以进行回滚。

1
kubectl edit rs myapp

将其中镜像版本从 v1 改为 v2 ,查看 rs 信息,发现镜像版本已经变成了v2,但是访问结果去还是 v1,这时需要重建 Pod 才能生效。

1
2
3
[root@k8s001 rexyan]# kubectl get rs -o wide 
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp 2 2 2 58m myapp-container ikubernetes/myapp:v2 app=myapp,release=test

或者选择之前的命令 set image 进行镜像升级。

Deployment

Deployment 是目前用来管理无状态应用的做好的控制器。deployment 简称为 deploy。 deploy.spec.strategy 表示更新策略,deploy.spec.strategy.type 支持两种更新,分别为 Recreate (重新创建) 和 RollingUpdate(滚动更新)默认是 RollingUpdate。当 deploy.spec.strategy.type 是 RollingUpdate 时,还可以配置 deploy.spec.strategy.type.RollingUpdate 字段,这个字段用来控制更新力度,共有两种值,分别为 maxSurge(更新过程中,超出目标副本数的数量,可为数字或者百分比) 和 maxUnavailable (最多有几个不可用)。我们可以控制这里的更新力度来实现不同的发布,例如金丝雀发布,蓝绿发布等。deploy.spec.revisionHistoryLimit 表示滚动更新中最多保存过去几个历史版本,这些历史版本可用于回滚。deployment 通过控制 ReplicaSet 来控制 Pod。

创建资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80

创建 deploy, apply 属于声明式创建,既可以创建,也可以用于更新。

1
2
[root@k8s001 rexyan]# kubectl apply -f deploy-demo.yaml 
deployment.apps/myapp-deploy created

查看 deploy 会发现刚刚的已经创建好了

1
2
3
[root@k8s001 rexyan]# kubectl get deploy 
NAME READY UP-TO-DATE AVAILABLE AGE
myapp-deploy 2/2 2

查看 ReplicaSet 也会看到对应的两个,因为 deployment 是依赖 ReplicaSet 的,基于 ReplicaSet 之上。后面的 67b6dfcd8 模版的 hash值,而不是随机的字符串。

1
2
3
[root@k8s001 rexyan]# kubectl get rs
NAME DESIRED CURRENT READY AGE
myapp-deploy-67b6dfcd8 2 2 2 6m33s

查看 Pod, Pod 的名称是 myapp-deploy-67b6dfcd8-xxxx,格式为 deployment 的名字 + ReplicaSet hash + 随机数。

1
2
3
4
[root@k8s001 rexyan]# kubectl get pods 
NAME READY STATUS RESTARTS AGE
myapp-deploy-67b6dfcd8-flnxl 1/1 Running 0 11m
myapp-deploy-67b6dfcd8-r6stl 1/1 Running 0 11m

修改副本数

修改 yaml 脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80

之后查看 Pod 的信息,发现名称部分 myapp-deploy-67b6dfcd8 依然没有变化,

1
2
[root@k8s001 rexyan]# kubectl apply -f deploy-demo.yaml 
deployment.apps/myapp-deploy configured

1
2
3
4
5
[root@k8s001 rexyan]# kubectl get pods 
NAME READY STATUS RESTARTS AGE
myapp-deploy-67b6dfcd8-flnxl 1/1 Running 0 15m
myapp-deploy-67b6dfcd8-nm9bs 1/1 Running 0 7s
myapp-deploy-67b6dfcd8-r6stl 1/1 Running 0 15m

查看 deploy 的详细信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[root@k8s001 rexyan]# kubectl  describe deploy myapp-deploy
Name: myapp-deploy
Namespace: default
CreationTimestamp: Tue, 28 May 2019 22:22:57 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"myapp-deploy","namespace":"default"},"spec":{"replicas":3...
Selector: app=myapp,release=canary
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=myapp
release=canary
Containers:
myapp:
Image: ikubernetes/myapp:v1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Progressing True NewReplicaSetAvailable
Available True MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet: myapp-deploy-67b6dfcd8 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 19m deployment-controller Scaled up replica set myapp-deploy-67b6dfcd8 to 2
Normal ScalingReplicaSet 4m19s deployment-controller Scaled up replica set myapp-deploy-67b6dfcd8 to 3

apply 会自动将每一次版本的变化添加到 Annotations 当中。apply 的 StrategyType(更新方式)RollingUpdate(滚动更新)且最多可用和最多不可用分别为 RollingUpdateStrategy: 25% max unavailable, 25% max surge。

滚动更新

deploy 的 apply 方式更新,Pod 最大可以用和不可用的数量分别是 25%。我们可以使用 -w命令来查看整个更新的过程。

终端1:编辑配置文件,将副本数量调整为5 (当前为3)

1
[root@k8s001 rexyan]# vim deploy-demo.yaml
1
[root@k8s001 rexyan]# kubectl apply -f deploy-demo.yaml

终端2:可以看到有创建了两个 Pod,以此来满足 5 个的数量。

1
2
3
4
5
6
7
8
9
10
[root@k8s001 ~]# kubectl get pods -w 
NAME READY STATUS RESTARTS AGE
myapp-deploy-67b6dfcd8-wsmxz 0/1 Pending 0 0s
myapp-deploy-67b6dfcd8-wsmxz 0/1 Pending 0 0s
myapp-deploy-67b6dfcd8-fxqvx 0/1 Pending 0 0s
myapp-deploy-67b6dfcd8-fxqvx 0/1 Pending 0 0s
myapp-deploy-67b6dfcd8-wsmxz 0/1 ContainerCreating 0 0s
myapp-deploy-67b6dfcd8-fxqvx 0/1 ContainerCreating 0 0s
myapp-deploy-67b6dfcd8-wsmxz 1/1 Running 0 1s
myapp-deploy-67b6dfcd8-fxqvx 1/1 Running 0 1s

如果此时再次修改配置文件,将镜像从 image: ikubernetes/myapp:v1 升级为 image: ikubernetes/myapp:v2,则现象为, 这个就是整个滚动更新的过程,可以看到 Pod 的整个创建和结束的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
myapp-deploy-675558bfc5-g4j5t   0/1     Pending             0          0s
myapp-deploy-675558bfc5-g4j5t 0/1 Pending 0 0s
myapp-deploy-675558bfc5-kkl22 0/1 Pending 0 0s
myapp-deploy-675558bfc5-kkl22 0/1 Pending 0 0s
myapp-deploy-67b6dfcd8-mgh8z 1/1 Terminating 0 2m3s
myapp-deploy-675558bfc5-g4j5t 0/1 ContainerCreating 0 0s
myapp-deploy-675558bfc5-h8c2c 0/1 Pending 0 0s
myapp-deploy-675558bfc5-h8c2c 0/1 Pending 0 0s
myapp-deploy-675558bfc5-kkl22 0/1 ContainerCreating 0 0s
myapp-deploy-675558bfc5-h8c2c 0/1 ContainerCreating 0 0s
myapp-deploy-67b6dfcd8-mgh8z 0/1 Terminating 0 2m3s
myapp-deploy-675558bfc5-g4j5t 1/1 Running 0 2s
myapp-deploy-67b6dfcd8-f5fgw 1/1 Terminating 0 2m5s
myapp-deploy-675558bfc5-4m4nb 0/1 Pending 0 0s
myapp-deploy-675558bfc5-4m4nb 0/1 Pending 0 0s
myapp-deploy-675558bfc5-4m4nb 0/1 ContainerCreating 0 0s
myapp-deploy-675558bfc5-kkl22 1/1 Running 0 2s
myapp-deploy-67b6dfcd8-mzftf 1/1 Terminating 0 2m5s
myapp-deploy-675558bfc5-b2lj5 0/1 Pending 0 0s
myapp-deploy-675558bfc5-b2lj5 0/1 Pending 0 0s
myapp-deploy-675558bfc5-b2lj5 0/1 ContainerCreating 0 0s
myapp-deploy-675558bfc5-h8c2c 1/1 Running 0 3s
myapp-deploy-675558bfc5-b2lj5 1/1 Running 0 1s
myapp-deploy-67b6dfcd8-f5fgw 0/1 Terminating 0 2m6s
myapp-deploy-67b6dfcd8-bktzd 1/1 Terminating 0 2m6s
myapp-deploy-67b6dfcd8-flnxl 1/1 Terminating 0 46m
myapp-deploy-67b6dfcd8-mzftf 0/1 Terminating 0 2m6s
myapp-deploy-675558bfc5-4m4nb 1/1 Running 0 1s
myapp-deploy-67b6dfcd8-flnxl 0/1 Terminating 0 46m
myapp-deploy-67b6dfcd8-bktzd 0/1 Terminating 0 2m7s
myapp-deploy-67b6dfcd8-f5fgw 0/1 Terminating 0 2m10s
myapp-deploy-67b6dfcd8-f5fgw 0/1 Terminating 0 2m10s
myapp-deploy-67b6dfcd8-mgh8z 0/1 Terminating 0 2m10s
myapp-deploy-67b6dfcd8-mgh8z 0/1 Terminating 0 2m10s
myapp-deploy-67b6dfcd8-mzftf 0/1 Terminating 0 2m10s
myapp-deploy-67b6dfcd8-mzftf 0/1 Terminating 0 2m10s
myapp-deploy-67b6dfcd8-flnxl 0/1 Terminating 0 46m
myapp-deploy-67b6dfcd8-flnxl 0/1 Terminating 0 46m
myapp-deploy-67b6dfcd8-bktzd 0/1 Terminating 0 2m20s
myapp-deploy-67b6dfcd8-bktzd 0/1 Terminating 0 2m20s

这时查看 rs 的信息,就会看到有两个 rs。不同点在于镜像的版本一个是v1,期待个数,当前可以个数等全部为0,另一个版本为 v2。v1 的存在是让我们可以回滚。

1
2
3
4
[root@k8s001 rexyan]# kubectl  get rs -o wide 
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp-deploy-675558bfc5 5 5 5 2m58s myapp ikubernetes/myapp:v2 app=myapp,pod-template-hash=675558bfc5,release=canary
myapp-deploy-67b6dfcd8 0 0 0 49m myapp ikubernetes/myapp:v1 app=myapp,pod-template-hash=67b6dfcd8,release=canary

金丝雀发布

修改更新过程中最大更新数(max surge)为 1个, 最大可减少数(max unavailable)为 0 ,这就意味着,在目前已经有的 Pod 的基础上,最多可以存在 6 个Pod,最少那就是 5 个。这时我们要实现当其创建出地 6 个的时候,将其发布暂停(此时有1个新的,5个旧的)那一个新的服务其实就是创建出的金丝雀。确认金丝雀没问题之后,让刚刚暂停住的更新继续执行,完成发布。

1. 修改 yaml 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 5
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v2
ports:
- name: http
containerPort: 80
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
1
[root@k8s001 rexyan]# kubectl apply -f deploy-demo.yaml

2. 查看详细信息, 发现已经修改了。

1
2
3
4
5
6
[root@k8s001 rexyan]# kubectl describe deploy myapp-deploy
......
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 0 max unavailable, 1 max surge
......

3. 修改镜像版本为 v3,并让其执行更新之后暂停。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 5
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v3
ports:
- name: http
containerPort: 80
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0

执行更新,并且更新后暂定

1
2
3
[root@k8s001 rexyan]# kubectl apply -f deploy-demo.yaml && kubectl rollout pause deploy myapp-deploy
deployment.apps/myapp-deploy configured
deployment.extensions/myapp-deploy paused

可以看到最后一个 Pod 是新建出来的,并没有继续往下滚动更新执行删除,而是被暂停了。

1
2
3
4
5
6
7
8
[root@k8s001 rexyan]# kubectl get pods 
NAME READY STATUS RESTARTS AGE
myapp-deploy-675558bfc5-4m4nb 1/1 Running 0 64m
myapp-deploy-675558bfc5-b2lj5 1/1 Running 0 64m
myapp-deploy-675558bfc5-g4j5t 1/1 Running 0 64m
myapp-deploy-675558bfc5-h8c2c 1/1 Running 0 64m
myapp-deploy-675558bfc5-kkl22 1/1 Running 0 64m
myapp-deploy-7f577979c8-v2ljw 1/1 Running 0 24s

这时可以确认 v3 版本的程序有没有问题(验证金丝雀),如果没有问题之后就可以继续执行更新过程。我们也可以查看更新过程。

1
2
[root@k8s001 rexyan]# kubectl rollout status deploy myapp-deploy 
Waiting for deployment "myapp-deploy" rollout to finish: 1 out of 5 new replicas have been updated...

上面查看状态,显示的意思是,等待部署 myapp-deploy 5 个副本,已经完成了一个。

4. 继续执行更新

1
2
[root@k8s001 rexyan]# kubectl rollout resume deploy myapp-deploy 
deployment.extensions/myapp-deploy resumed

再次查看更新状态,发现提示已经更新完成了。

1
2
[root@k8s001 rexyan]# kubectl rollout status deploy myapp-deploy 
deployment "myapp-deploy" successfully rolled out

查看 Pod,以前的老版本 Pod 都被删除了。

1
2
3
4
5
6
7
[root@k8s001 rexyan]# kubectl get pods 
NAME READY STATUS RESTARTS AGE
myapp-deploy-7f577979c8-fbsvm 1/1 Running 0 26s
myapp-deploy-7f577979c8-mq26d 1/1 Running 0 30s
myapp-deploy-7f577979c8-r68x5 1/1 Running 0 27s
myapp-deploy-7f577979c8-v2ljw 1/1 Running 0 8m19s
myapp-deploy-7f577979c8-wpktg 1/1 Running 0 28s

查看 rs 的信息,发现 rs 已经有了三个,最新的为 v3 版本的镜像。

1
2
3
4
5
[root@k8s001 rexyan]# kubectl get rs -o wide 
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp-deploy-675558bfc5 0 0 0 72m myapp ikubernetes/myapp:v2 app=myapp,pod-template-hash=675558bfc5,release=canary
myapp-deploy-67b6dfcd8 0 0 0 118m myapp ikubernetes/myapp:v1 app=myapp,pod-template-hash=67b6dfcd8,release=canary
myapp-deploy-7f577979c8 5 5 5 8m42s myapp ikubernetes/myapp:v3 app=myapp,pod-template-hash=7f577979c8,release=canary

至此,就完成了一个金丝雀发布。

回滚操作

查看当前可以回滚的版本

1
2
3
4
5
6
[root@k8s001 ~]# kubectl rollout history deploy myapp-deploy 
deployment.extensions/myapp-deploy
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>

当前处于最新的第三个版本,我们可以使用 –to-revision 指定回退到的版本,例如回退到第一版本

1
2
[root@k8s001 ~]# kubectl rollout undo deploy myapp-deploy --to-revision=1
deployment.extensions/myapp-deploy rolled back

再次查看 rollout history 会发现第一个版本已经没有了,对应的是第四个版本(其实这里的第四版本就是第一个版本)

1
2
3
4
5
6
[root@k8s001 ~]# kubectl rollout history deploy myapp-deploy 
deployment.extensions/myapp-deploy
REVISION CHANGE-CAUSE
2 <none>
3 <none>
4 <none>

查看 rs的详细信息,也会发现当前版本已经回到了第一版

1
2
3
4
5
6
7
[root@k8s001 ~]# kubectl  get rs -o wide 
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp-deploy-675558bfc5 0 0 0 22h myapp ikubernetes/myapp:v2 app=myapp,pod-template-hash=675558bfc5,release=canary
myapp-deploy-67b6dfcd8 5 5 5 22h myapp ikubernetes/myapp:v1 app=myapp,pod-template-hash=67b6dfcd8,release=canary
myapp-deploy-7f577979c8 0 0 0 20h myapp ikubernetes/myapp:v3 app=myapp,pod-template-hash=7f577979c8,release=canary
[root@k8s001 ~]#
[root@k8s001 ~]#

DaemonSet

在集群中的每一个节点或者满足条件的节点之上,有且仅运行一个 Pod 副本。DaemonSet 和 Deployment 一样,所控制的 Pod 也是无状态的,且两者应用一直在后台运行(就算是任务完成 Pod 也不能退出)。简称 ds

创建资源

创建资源,DaemonSet 在每一个 node 上只运行一个副本,所有不能指定 replicas, 其余的定义方式和 deploy 差不多,env 是定义环境变量,这里定义是因为镜像使用所需。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: myapp-ds
namespace: default
spec:
selector:
matchLabels:
app: filebeat
release: stable
template:
metadata:
labels:
app: filebeat
release: stable
spec:
containers:
- name: filebeat
image: ikubernetes/filebeat:5.6.5-alpine
env:
- name: REDIS_HOST
value: redis.default.svc.cluster.local
- name: REDIS_LOG_LEVEL
value: info
1
2
[root@k8s001 rexyan]# kubectl create -f ds-demo.yaml 
daemonset.apps/myapp-ds created

创建资源之后就可以看到在两个节点之上分别运行了一个 Pod

1
2
3
4
5
6
7
8
9
[root@k8s001 rexyan]# kubectl get pods -o wide 
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-deploy-67b6dfcd8-42x9q 1/1 Running 0 45m 10.244.2.11 k8s003 <none> <none>
myapp-deploy-67b6dfcd8-9vjwh 1/1 Running 0 44m 10.244.1.17 k8s002 <none> <none>
myapp-deploy-67b6dfcd8-b45pt 1/1 Running 0 44m 10.244.2.13 k8s003 <none> <none>
myapp-deploy-67b6dfcd8-c2v69 1/1 Running 0 45m 10.244.1.16 k8s002 <none> <none>
myapp-deploy-67b6dfcd8-cr5hj 1/1 Running 0 44m 10.244.2.12 k8s003 <none> <none>
myapp-ds-kf892 1/1 Running 0 14s 10.244.2.14 k8s003 <none> <none>
myapp-ds-zb82c 1/1 Running 0 14s 10.244.1.18 k8s002 <none> <none>

更新方式

查看 ds 的更新策略可以发现,ds 支持 RollingUpdate(滚动更新) 和 OnDelete(删除后更新) 两种更新,默认为 OnDelete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@k8s001 rexyan]# kubectl explain ds.spec.updateStrategy
KIND: DaemonSet
VERSION: extensions/v1beta1

RESOURCE: updateStrategy <Object>

DESCRIPTION:
An update strategy to replace existing DaemonSet pods with new pods.

FIELDS:
rollingUpdate <Object>
Rolling update config params. Present only if type = "RollingUpdate".

type <string>
Type of daemon set update. Can be "RollingUpdate" or "OnDelete". Default is
OnDelete.

当 type 是 RollingUpdate 的时候,ds.spec.updateStrategy.rollingUpdate 下只能定义 maxUnavailable 字段。即只能定义最大可减少数(max unavailable)也就是只能删除后才能更新(这也符合 DaemonSet 在 Node 上只能有一个的原则)。

Job

按照用户的定义,完成指定任务,任务正常完成后 Pod 就会正常退出,若任务没有完成 Pod 就退出,则 Pod 会被重新创建。

CronJob

周期性运行

StatefulSet

有状态应用控制器

1
2